package com.codedancer.campus.manager.service.impl;

import cn.afterturn.easypoi.entity.vo.NormalExcelConstants;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.view.PoiBaseView;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.codedancer.campus.common.exception.BusinessException;
import com.codedancer.campus.common.utils.UUIDGenerator;
import com.codedancer.campus.enums.DynamicStatus;
import com.codedancer.campus.enums.SystemMessageType;
import com.codedancer.campus.manager.mq.producer.MqSendMessageProducer;
import com.codedancer.campus.manager.service.IDynamicService;
import com.codedancer.campus.manager.service.bo.dynamic.DynamicExamineBo;
import com.codedancer.campus.manager.service.bo.dynamic.DynamicPageSearchBo;
import com.codedancer.campus.manager.service.excel.DynamicExcel;
import com.codedancer.campus.manager.service.model.SystemMessageMqParamModel;
import com.codedancer.campus.manager.service.vo.dynamic.DynamicPageVo;
import com.codedancer.campus.manager.service.vo.dynamic.DynamicVo;
import com.codedancer.campus.mapper.CircleLabelMapper;
import com.codedancer.campus.mapper.CircleMapper;
import com.codedancer.campus.mapper.DynamicCircleLabelMapper;
import com.codedancer.campus.mapper.DynamicExamineRecordMapper;
import com.codedancer.campus.mapper.DynamicImageMapper;
import com.codedancer.campus.mapper.DynamicMapper;
import com.codedancer.campus.mapper.SchoolMapper;
import com.codedancer.campus.mapper.SystemMessageMapper;
import com.codedancer.campus.mapper.UserFollowMapper;
import com.codedancer.campus.mapper.UserMapper;
import com.codedancer.campus.po.Circle;
import com.codedancer.campus.po.CircleLabel;
import com.codedancer.campus.po.Dynamic;
import com.codedancer.campus.po.DynamicCircleLabel;
import com.codedancer.campus.po.DynamicExamineRecord;
import com.codedancer.campus.po.DynamicImage;
import com.codedancer.campus.po.School;
import com.codedancer.campus.po.User;
import com.codedancer.campus.qo.dynamic.DynamicSearchQo;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class DynamicServiceImpl implements IDynamicService {

    @Autowired
    private DynamicMapper dynamicMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private SchoolMapper schoolMapper;
    @Autowired
    private CircleMapper circleMapper;
    @Autowired
    private CircleLabelMapper circleLabelMapper;
    @Autowired
    private DynamicCircleLabelMapper dynamicCircleLabelMapper;
    @Autowired
    private DynamicImageMapper dynamicImageMapper;
    @Autowired
    private DynamicExamineRecordMapper dynamicExamineRecordMapper;
    @Autowired
    private SystemMessageMapper systemMessageMapper;
    @Autowired
    private UserFollowMapper userFollowMapper;
    @Autowired
    private MqSendMessageProducer mqSendMessageProducer;

    /**
     * 分页查询动态
     *
     * @param dynamicPageSearchBo
     * @return
     */
    @Override
    public IPage<DynamicPageVo> page(DynamicPageSearchBo dynamicPageSearchBo) {
        DynamicSearchQo dynamicSearchQo = BeanUtil
            .copyProperties(dynamicPageSearchBo, DynamicSearchQo.class);
        IPage<Dynamic> dynamicIPage = dynamicMapper.page2Manager(
            new Page<Dynamic>(dynamicPageSearchBo.getPage(), dynamicPageSearchBo.getSize()),
            dynamicSearchQo);
        List<DynamicPageVo> dynamicPageVos;
        IPage<DynamicPageVo> dynamicPageVoIPage = new Page<>();
        dynamicPageVos = dynamicIPage.getRecords().stream().map(dynamic -> {
            DynamicPageVo dynamicPageVo = BeanUtil.copyProperties(dynamic, DynamicPageVo.class);
            dynamicPageVo.setPublishUserNickName(dynamic.getPublishUser().getNickName());
            dynamicPageVo.setPublishSchoolName(dynamic.getPublishSchool().getName());
            dynamicPageVo.setCircleName(dynamic.getPublishCircle().getTitle());
            // 获取动态绑定的标签
            List<DynamicCircleLabel> dynamicCircleLabels = dynamicCircleLabelMapper.selectListByColumn(
                "dynamic_uuid", dynamic.getUuid());
            // 获取标签
            List<CircleLabel> circleLabels = circleLabelMapper.selectListByUuids(
                dynamicCircleLabels.stream().map(DynamicCircleLabel::getCircleLabelUuid).collect(
                    Collectors.toList()));
            dynamicPageVo
                .setLabelNames(circleLabels.stream().map(CircleLabel::getName).collect(
                    Collectors.toList()));
            return dynamicPageVo;
        }).collect(Collectors.toList());
        dynamicPageVoIPage.setTotal(dynamicIPage.getTotal());
        dynamicPageVoIPage.setRecords(dynamicPageVos);
        return dynamicPageVoIPage;
    }

    /**
     * 动态详情
     *
     * @param uuid
     * @return
     */
    @Override
    public DynamicVo detail(String uuid) {
        Dynamic dynamic = dynamicMapper.findById(uuid)
            .orElseThrow(() -> new BusinessException("动态不存在"));
        DynamicVo dynamicVo = BeanUtil.copyProperties(dynamic, DynamicVo.class);
        User user = userMapper.selectById(dynamic.getPublishUserUuid());
        dynamicVo.setPublishUserNickName(user.getNickName());
        School school = schoolMapper.selectById(dynamic.getPublishSchoolUuid());
        dynamicVo.setPublishSchoolName(school.getName());
        Circle circle = circleMapper.selectById(dynamic.getCircleUuid());
        dynamicVo.setCircleName(circle.getTitle());
        List<DynamicCircleLabel> dynamicCircleLabels = dynamicCircleLabelMapper
            .selectListByColumn("dynamic_uuid", uuid);
        List<CircleLabel> circleLabels = circleLabelMapper.selectListByUuids(
            dynamicCircleLabels.stream().map(DynamicCircleLabel::getCircleLabelUuid)
                .collect(Collectors.toList()));
        dynamicVo.setLabelNames(
            circleLabels.stream().map(CircleLabel::getName).collect(Collectors.toList()));
        // 查询动态图片
        List<DynamicImage> dynamicImages = dynamicImageMapper
            .selectListByColumn("dynamic_uuid", uuid);
        dynamicVo.setImages(
            dynamicImages.stream().map(DynamicImage::getImageUrl).collect(Collectors.toList()));
        // 查询最近一条审核记录
        DynamicExamineRecord dynamicExamineRecord = dynamicExamineRecordMapper
            .selectLastExamineRecord(uuid);
        if (ObjectUtil.isNotEmpty(dynamicExamineRecord)) {
            dynamicVo.setLatestNoPassReason(dynamicExamineRecord.getNoPassReason());
        }
        return dynamicVo;
    }

    /**
     * 审核未通过
     *
     * @param dynamicExamineBo
     */
    @Override
    public void noPass(DynamicExamineBo dynamicExamineBo) {
        Dynamic dynamic = dynamicMapper.findById(dynamicExamineBo.getUuid())
            .orElseThrow(() -> new BusinessException("动态不存在"));
        if (dynamic.examineCountIsGtFive()) {
            throw new BusinessException("审核次数已大于五次，不能审核");
        }
        dynamic.setExamineCount(dynamic.getExamineCount() + 1);
        dynamic.setStatus(DynamicStatus.NOT_PASS);
        dynamicMapper.updateById(dynamic);
        // 保存审核记录
        DynamicExamineRecord dynamicExamineRecord = DynamicExamineRecord.builder()
            .uuid(UUIDGenerator.getUUID())
            .dynamicUuid(dynamic.getUuid())
            .examineAdminUuid(dynamicExamineBo.getCurrentUserUuid())
            .isPass(false)
            .noPassReason(dynamicExamineBo.getNoPassReason()).build();
        dynamicExamineRecordMapper.insert(dynamicExamineRecord);
        // 保存系统消息
        SystemMessageMqParamModel systemMessageMqParamModel = SystemMessageMqParamModel.builder()
            .messageType(SystemMessageType.DYNAMIC_EXAMINE)
            .receiveUserUuid(dynamic.getPublishUserUuid())
            .content("【" + dynamic.getContent() + "】审核未通过，原因为："
                + dynamicExamineBo.getNoPassReason()).build();
        mqSendMessageProducer.sendSystemMessage(JSONUtil.toJsonStr(systemMessageMqParamModel));
    }

    /**
     * 审核通过
     *
     * @param dynamicExamineBo
     */
    @Override
    public void pass(DynamicExamineBo dynamicExamineBo) {
        Dynamic dynamic = dynamicMapper.findById(dynamicExamineBo.getUuid())
            .orElseThrow(() -> new BusinessException("动态不存在"));
        if (dynamic.examineCountIsGtFive()) {
            throw new BusinessException("审核次数已大于五次，不能审核");
        }
        User user = userMapper.selectById(dynamic.getPublishUserUuid());
        dynamic.setExamineCount(dynamic.getExamineCount() + 1);
        dynamic.setStatus(DynamicStatus.PASSED);
        dynamicMapper.updateById(dynamic);
        // 保存审核记录
        DynamicExamineRecord dynamicExamineRecord = DynamicExamineRecord.builder()
            .uuid(UUIDGenerator.getUUID())
            .dynamicUuid(dynamic.getUuid())
            .examineAdminUuid(dynamicExamineBo.getCurrentUserUuid())
            .isPass(true)
            .noPassReason(dynamicExamineBo.getNoPassReason()).build();
        dynamicExamineRecordMapper.insert(dynamicExamineRecord);
        // 保存系统消息
        SystemMessageMqParamModel systemMessageMqParamModel = SystemMessageMqParamModel.builder()
            .messageType(SystemMessageType.DYNAMIC_EXAMINE)
            .receiveUserUuid(dynamic.getPublishUserUuid())
            .content("【" + dynamic.getContent() + "】审核通过").build();
        mqSendMessageProducer.sendSystemMessage(JSONUtil.toJsonStr(systemMessageMqParamModel));
        // 给粉丝推送消息
        SystemMessageMqParamModel dynamicSystemMessageMqParamModel = SystemMessageMqParamModel
            .builder()
            .messageType(SystemMessageType.DYNAMIC_PUBLISH)
            .dynamicPublishUserUuid(dynamic.getPublishUserUuid()).build();
        mqSendMessageProducer.sendSystemMessage(JSONUtil.toJsonStr(systemMessageMqParamModel));
    }

    /**
     * 开启评论
     *
     * @param uuid
     */
    @Override
    public void openComment(String uuid) {
        Dynamic dynamic = dynamicMapper.findById(uuid)
            .orElseThrow(() -> new BusinessException("动态不存在"));
        dynamic.setIsOpenComment(true);
        dynamicMapper.updateById(dynamic);
    }

    /**
     * 关闭评论
     *
     * @param uuid
     */
    @Override
    public void closeComment(String uuid) {
        Dynamic dynamic = dynamicMapper.findById(uuid)
            .orElseThrow(() -> new BusinessException("动态不存在"));
        dynamic.setIsOpenComment(false);
        dynamicMapper.updateById(dynamic);
    }

    /**
     * 删除动态
     *
     * @param uuid
     */
    @Override
    public void delete(String uuid) {
        dynamicMapper.deleteById(uuid);
    }

    /**
     * 导出动态
     *
     * @param request
     * @param response
     * @param dynamicPageSearchBo
     */
    @Override
    public void export(HttpServletRequest request, HttpServletResponse response,
        DynamicPageSearchBo dynamicPageSearchBo) {
        log.info("开始导出动态数据");
        DynamicSearchQo dynamicSearchQo = BeanUtil
            .copyProperties(dynamicPageSearchBo, DynamicSearchQo.class);
        // 查询需要导出的动态
        List<Dynamic> dynamics = dynamicMapper.listExportData(dynamicSearchQo);
        // 组装数据
        List<DynamicExcel> dynamicExcels = assembleData(dynamics);
        Map<String, Object> map = new HashMap<>();
        ExportParams params = new ExportParams("动态列表", "动态列表", ExcelType.HSSF);
        map.put(NormalExcelConstants.DATA_LIST, dynamicExcels);
        map.put(NormalExcelConstants.CLASS, DynamicExcel.class);
        map.put(NormalExcelConstants.PARAMS, params);
        map.put(NormalExcelConstants.FILE_NAME, "动态列表" + DateUtil.today());
        PoiBaseView.render(map, request, response, NormalExcelConstants.EASYPOI_EXCEL_VIEW);
        log.info("动态数据导出完成");
    }

    /**
     * 批量删除
     *
     * @param uuids
     */
    @Override
    public void batchDelete(List<String> uuids) {
        dynamicMapper.deleteBatchIds(uuids);
    }

    /**
     * 分页查询某个圈子下的动态
     *
     * @param dynamicPageSearchBo
     * @return
     */
    @Override
    public IPage<DynamicPageVo> pageByCircleUuid(DynamicPageSearchBo dynamicPageSearchBo) {
        if (!circleMapper.existsByUuId(dynamicPageSearchBo.getCircleUuid())) {
            throw new BusinessException("圈子不存在");
        }
        DynamicSearchQo dynamicSearchQo = BeanUtil
            .copyProperties(dynamicPageSearchBo, DynamicSearchQo.class);
        IPage<Dynamic> dynamicIPage = dynamicMapper.pageByCircleUuid2Manager(
            new Page<Dynamic>(dynamicPageSearchBo.getPage(), dynamicPageSearchBo.getSize()),
            dynamicSearchQo);
        List<DynamicPageVo> dynamicPageVos;
        IPage<DynamicPageVo> dynamicPageVoIPage = new Page<>();
        dynamicPageVos = dynamicIPage.getRecords().stream().map(dynamic -> {
            DynamicPageVo dynamicPageVo = BeanUtil.copyProperties(dynamic, DynamicPageVo.class);
            dynamicPageVo.setPublishUserNickName(dynamic.getPublishUser().getNickName());
            dynamicPageVo.setPublishUserAvatar(dynamic.getPublishUser().getAvatar());
            dynamicPageVo.setPublishSchoolName(dynamic.getPublishSchool().getName());
            dynamicPageVo
                .setLabelNames(dynamic.getCircleLabels().stream().map(CircleLabel::getName).collect(
                    Collectors.toList()));
            return dynamicPageVo;
        }).collect(Collectors.toList());
        dynamicPageVoIPage.setTotal(dynamicIPage.getTotal());
        dynamicPageVoIPage.setRecords(dynamicPageVos);
        return dynamicPageVoIPage;
    }

    /**
     * 组装数据 将Dynamic转换成DynamicExcel
     *
     * @param dynamics
     * @return
     */
    private List<DynamicExcel> assembleData(List<Dynamic> dynamics) {
        return dynamics.stream().map(dynamic -> {
            DynamicExcel dynamicExcel = BeanUtil.copyProperties(dynamic, DynamicExcel.class);
            dynamicExcel.setPublishUserNickName(dynamic.getPublishUser().getNickName());
            dynamicExcel.setPublishSchoolName(dynamic.getPublishSchool().getName());
            dynamicExcel.setPublishCircleName(dynamic.getPublishCircle().getTitle());
            dynamicExcel.setPublishType(dynamic.getType().getName());
            dynamicExcel.setStatus(dynamic.getStatus().getName());
            dynamicExcel.setIsOpenComment(dynamic.getIsOpenComment() ? "开启" : "关闭");
            dynamicExcel.setIsHide(dynamic.getIsHide() ? "隐藏" : "显示");
            List<String> labelNames = dynamic.getCircleLabels().stream().map(CircleLabel::getName)
                .collect(
                    Collectors.toList());
            dynamicExcel.setLabel(StrUtil.join(",", labelNames));
            return dynamicExcel;
        }).collect(Collectors.toList());
    }
}
